home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus Extra 1997 #1
/
Amiga Plus Extra 1997 #1.iso
/
programme
/
tools
/
leoutils
/
leotune.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-25
|
18KB
|
722 lines
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define VERSION "4.14"
#if defined _AMIGA || defined AMIGA
#include <dos/dos.h>
#if defined __SASC
#include <proto/dos.h>
#else
#include <clib/dos_protos.h>
#endif
#else
#include <time.h>
#endif
#include "LeoLib.h"
#define DIRECTORY "Fortunes:"
#define FORTUNEBASE "LeoTunes"
#define INDEX ".idx"
#define INDEX4 ".idx4"
#define TRUE 1
#define FALSE 0
#define WW_DEFWIDTH 78
/* The following definitions are for ANSI C compilers with bad stdio.h */
#if !defined SEEK_SET
#define SEEK_SET 0
#endif
#if !defined _IOFBF
#define _IOFBF 0
#endif
/* AMIGA VERSION STRING */
#if defined _AMIGA || defined AMIGA
static char *Version = "$VER:LeoTune " VERSION
#if defined __SASC
" " __AMIGADATE__ " ©1992-96 Leopold-Soft, leopold@cs.tut.fi"
#endif
;
#endif
/* MY OWN TYPE DEFINITIONS */
#if !defined _AMIGA && !defined AMIGA
typedef short BOOL;
#endif
typedef unsigned char uchar;
/* PROTOTYPES */
static void CreateIndexFile(void);
static void ShowFortune(int Number);
static int ShowFortuneFromMem(FILE* OutFile, uchar *Text, long Length);
static uchar ToIso11(uchar c);
static void GrepFortunes(uchar *GrepStr, BOOL CaseSensitive);
#if defined _AMIGA || defined AMIGA
static ULONG GetAmigaTicks(void);
#endif
static void Bufferize(FILE *File); /* Only one file may be bufferized at a time */
static void PutInit(FILE *OutFile);
static void PutWord(uchar *Str);
static void PutEOL(void);
static int PutEnd(void); /* returns lines handled */
static void PutTab(void);
static void PutSpace(void);
static void PutSetWidth(int Width);
static void PutPurgeSpace(void);
static void PutSetIndent(BOOL On);
static void PutDoIndent(void);
/* VARIABLES */
static char FFile[1024], FIndex[1024], FIndex4[1024];
static int CurrArg = 0, WordWrapWidth = WW_DEFWIDTH;
static BOOL WantedIndexRecount = FALSE;
static BOOL LongOutputMode = TRUE;
static BOOL SignatureMode = FALSE;
static BOOL Iso11 = FALSE, Grep = FALSE, GrepCaseSensitivity;
static int WantedFortune = 0, GrepArg;
static char *Directory;
static void *InBuff = NULL;
static unsigned long FEnd0 =
(('\n' << 24) | ('%' << 16) | ('%' << 8) | '\n');
static unsigned long FEnd1 =
(('\n' << 24) | ('#' << 16) | ('#' << 8) | '\n');
/* MAIN PROGRAM */
int main(int argc, char **argv) {
static char *ColumnsStr;
static int Columns = 0;
if ((ColumnsStr = getenv("COLUMNS")) && (Columns = atoi(ColumnsStr)))
WordWrapWidth = Columns;
FFile[0] = '\000';
if (!(Directory = getenv("LEOTUNEDIR"))) {
if (Directory = getenv("HOME")) {
strcpy(FFile, Directory);
if (FFile[strlen(FFile)-1] != '/'
#if defined _AMIGA || defined AMIGA
&& FFile[strlen(FFile)-1] != ':'
#endif
)
strcat(FFile, "/");
strcat(FFile, "text/");
} else {
strcpy(FFile, DIRECTORY);
}
} else {
strcpy(FFile, Directory);
if (FFile[strlen(FFile)-1] != '/'
#if defined _AMIGA || defined AMIGA
&& FFile[strlen(FFile)-1] != ':'
#endif
)
strcat(FFile, "/");
}
strcat(FFile, FORTUNEBASE);
strcpy(FIndex, FFile);
strcat(FIndex, INDEX);
strcpy(FIndex4, FFile);
strcat(FIndex4, INDEX4);
while(++CurrArg < argc) {
if (!strcmp(argv[CurrArg],"-i") || !strcmp(argv[CurrArg],"index")) {
WantedIndexRecount = TRUE;
} else if (!strcmp(argv[CurrArg],"-s") || !strcmp(argv[CurrArg],"short")) {
LongOutputMode = FALSE;
} else if (!strcmp(argv[CurrArg],"-4") || !strcmp(argv[CurrArg],"sig")) {
SignatureMode = TRUE;
} else if (!strcmp(argv[CurrArg],"-7") || !strcmp(argv[CurrArg],"iso11")) {
Iso11 = TRUE;
} else if ((!strcmp(argv[CurrArg],"-t") || !strcmp(argv[CurrArg],"tune")) && argc > CurrArg) {
WantedFortune = atoi(argv[++CurrArg]);
if (WantedFortune < 1) {
fprintf(stderr, "\nWarning: %d is not a valid fortune number, ignoring...\n",
WantedFortune);
WantedFortune = 0;
}
} else if ((!strcmp(argv[CurrArg],"-g") || !strcmp(argv[CurrArg],"grep")) && argc > CurrArg) {
GrepArg = ++CurrArg;
Grep = TRUE;
GrepCaseSensitivity = FALSE;
} else if ((!strcmp(argv[CurrArg],"-G") || !strcmp(argv[CurrArg],"GREP")) && argc > CurrArg) {
GrepArg = ++CurrArg;
Grep = TRUE;
GrepCaseSensitivity = TRUE;
} else if ((!strcmp(argv[CurrArg],"-w") || !strcmp(argv[CurrArg],"width")) && argc > CurrArg) {
WordWrapWidth = atoi(argv[++CurrArg]);
} else if (!strcmp(argv[CurrArg],"-h") || !strcmp(argv[CurrArg],"?")) {
printf("\nLeofortune " VERSION " by Henrik Herranen " __DATE__ "\n\n"
"Usage: %s [?] | [-h] | [-i] | [-s] | [-4] | [filename]\n\n"
"-h or ?: Show this help page.\n"
"-i or index: Recreate the fortune index file. This option must\n"
" be used every time the fortune database is updated.\n"
"-s or short: Don't insert any empty lines.\n"
"-4 or sig : Use an index file with only the fortunes with\n"
" mostly 4 lines of less than 80 characters each.\n"
"-7 or iso11: Convert some 8-bit ANSI characters to their ISO 11\n"
" (Swedish translation table) equivalents. Replace\n"
" rest of the 8-bit characters with '?'\n"
"-t x or Show a specific fortune from the database. The\n"
" tune x: first fortune is numbered 1.\n"
"-g x or Displays all fortunes that have the string x in\n"
" grep x: themselves (case-insensitive).\n"
"-G x or Displays all fortunes that have the string x in\n"
" GREP x: themselves (case-sensitive).\n"
"-w x or Displays all word-wrapped in x columns. The default\n"
" width x: is 79 or whatever is in $COLUMNS\n"
"filename: the named file will be used as the fortune file.\n\n"
,argv[0]);
exit(EXIT_SUCCESS);
} else {
strcpy(FFile,argv[CurrArg]);
strcpy(FIndex,argv[CurrArg]);
strcat(FIndex,INDEX);
strcpy(FIndex4,argv[CurrArg]);
strcat(FIndex4,INDEX4);
}
}
if (WantedIndexRecount) CreateIndexFile();
else if (Grep) GrepFortunes((uchar *) argv[GrepArg], GrepCaseSensitivity);
else ShowFortune(WantedFortune);
return EXIT_SUCCESS;
}
/* CREATES INDEX FILES */
static void CreateIndexFile(void) {
static FILE *InFile,*InFile2,*OutFile,*OutFile4;
static long FortuneCount=0,FortuneCount4=0;
static int InC;
static long FortuneBeginAddress=0;
static long Width=0,Widest=0,Lines=0;
static int i;
static long OldFortuneAmount=0,OldFortuneAmount4=0;
static long WordWrappedFortunes, WordWrappedFortunes4;
static unsigned long Last4 = 0;
static long FortuneLength = 0, Loc = 0;
static long MaxFortuneLength = 0;
static uchar *FortuneText = NULL;
SignatureMode = TRUE;
if (!(InFile = fopen(FFile,"rb"))) {
fprintf(stderr,"Couldn't open fortune file %s for reading!\n",FFile);
exit(EXIT_FAILURE);
}
Bufferize(InFile);
if (InFile2 = fopen(FIndex,"rb")) {
fread(&OldFortuneAmount,1,sizeof(OldFortuneAmount),InFile2);
fclose(InFile2);
}
if (InFile2 = fopen(FIndex4,"rb")) {
fread(&OldFortuneAmount4,1,sizeof(OldFortuneAmount4),InFile2);
fclose(InFile2);
}
if (!(OutFile = fopen(FIndex,"wb"))) {
fprintf(stderr,"Couldn't open fortune file %s for writing!\n",FIndex);
exit(EXIT_FAILURE);
}
if (!(OutFile4 = fopen(FIndex4,"wb"))) {
fprintf(stderr,"Couldn't open fortune file %s for writing!\n",FIndex4);
exit(EXIT_FAILURE);
}
/* Leave some space for the # of fortunes */
for (i=0; i<sizeof(FortuneCount); i++) {
fputc('?',OutFile);
fputc('?',OutFile4);
}
do {
InC = fgetc(InFile);
Loc++;
FortuneLength++;
if (FortuneLength > MaxFortuneLength) {
static uchar *Tmp;
long OldFLen = MaxFortuneLength;
MaxFortuneLength = MaxFortuneLength * 120 / 100 + 100;
if (!(Tmp = malloc((size_t) MaxFortuneLength))) {
fprintf(stderr, "Couldn't allocate %d bytes!\n", FortuneLength);
exit(EXIT_FAILURE);
}
if (OldFLen) {
memcpy(Tmp, FortuneText, (size_t) OldFLen);
free (FortuneText);
}
FortuneText = Tmp;
}
FortuneText[FortuneLength-1] = InC;
Last4 = (Last4 << 8) | InC;
if (Last4 == FEnd0 || Last4 == FEnd1) {
FortuneLength -= 3;
FortuneCount++;
fwrite(&FortuneBeginAddress, 1, sizeof(FortuneBeginAddress), OutFile);
fwrite(&FortuneLength, 1, sizeof(FortuneLength), OutFile);
if (Last4 == FEnd1) WordWrappedFortunes++;
if (Last4 == FEnd0 && Widest < 80 && Lines < 5 ||
Last4 == FEnd1 && ShowFortuneFromMem(NULL, FortuneText, FortuneLength) < 5) {
FortuneCount4++;
fwrite(&FortuneBeginAddress, 1, sizeof(FortuneBeginAddress), OutFile4);
fwrite(&FortuneLength, 1, sizeof(FortuneLength), OutFile4);
if (Last4 == FEnd1) WordWrappedFortunes4++;
}
Width = 0; Widest = 0; Lines = 0;
FortuneBeginAddress = Loc;
FortuneLength = 0;
} else {
if (InC == '\n') {
if (Width > Widest) Widest = Width;
Width = 0;
Lines++;
} else if (InC == '\t') {
Width = (Width + 8) & ~7L;
} else {
Width++;
}
}
} while (InC != -1);
fseek(OutFile, 0, SEEK_SET);
fwrite(&FortuneCount, 1, sizeof(FortuneCount), OutFile);
fseek(OutFile4, 0, SEEK_SET);
fwrite(&FortuneCount4, 1, sizeof(FortuneCount4), OutFile4);
fclose(OutFile);
fclose(InFile);
printf("\n%d entries (%d+%d; %d new) created in %s\n"
"%d entries (%d+%d; %d new) created in %s\n\n",
FortuneCount,
WordWrappedFortunes, FortuneCount-WordWrappedFortunes,
FortuneCount-OldFortuneAmount, FIndex,
FortuneCount4,
WordWrappedFortunes4, FortuneCount4-WordWrappedFortunes4,
FortuneCount4-OldFortuneAmount4, FIndex4);
return;
}
/* DISPLAYS A FORTUNE */
static void ShowFortune(int FNumber) {
static long Random, i;
static FILE *InFile;
static long FortuneBeginAddress,FortuneLength,FortuneAmount;
static uchar *FortuneText;
if (SignatureMode) strcpy(FIndex, FIndex4);
if (!(InFile = fopen(FIndex,"rb"))) {
fprintf(stderr,"Couldn't open fortune file %s for reading!\n",FIndex);
exit(EXIT_FAILURE);
}
fread(&FortuneAmount,1,sizeof(FortuneAmount),InFile);
if (FNumber > 0) {
if (FNumber <= FortuneAmount) {
Random = FNumber - 1;
} else {
fprintf(stderr,"\nWarning: %d is not a valid fortune number (max=%d), ignoring...\n",
FNumber, FortuneAmount);
FNumber = 0;
}
}
if (!FNumber) {
#if defined _AMIGA || defined AMIGA
if (!(Random = (GetAmigaTicks() >> 1))) {
#else
if ((Random = time(NULL)) < 0) {
Random = 0;
#endif
fprintf(stderr, "System clock not set, resetting to fortune #0!\n");
} else {
Random %= FortuneAmount;
}
}
fseek(InFile, Random*(sizeof(FortuneBeginAddress)+sizeof(FortuneLength))+sizeof(FortuneAmount), SEEK_SET);
fread(&FortuneBeginAddress,1,sizeof(FortuneBeginAddress),InFile);
fread(&FortuneLength,1,sizeof(FortuneLength),InFile);
fclose(InFile);
if (!(InFile = fopen(FFile,"rb"))) {
fprintf(stderr, "Couldn't open fortune file %s for reading!\n",FFile);
exit(EXIT_FAILURE);
}
if(LongOutputMode) fputc('\n', stdout);
fseek(InFile, FortuneBeginAddress, SEEK_SET);
if (!(FortuneText = malloc((size_t) (FortuneLength+1)))) {
fprintf(stderr, "Couldn't allocate %d bytes!\n", FortuneLength);
exit(EXIT_FAILURE);
}
fread(FortuneText, 1, (size_t) (FortuneLength+1), InFile);
if (Iso11) {
for (i=0; i<FortuneLength; i++) {
FortuneText[i] = ToIso11(FortuneText[i]);
}
}
if (FortuneText[FortuneLength] == '%') { /* No WordWrap required */
fwrite(FortuneText, 1, (size_t) FortuneLength, stdout);
} else { /* WordWrap required */
ShowFortuneFromMem(stdout, FortuneText, FortuneLength);
} /* End of if (WordWrap) */
free(FortuneText);
if(LongOutputMode) fputc('\n', stdout);
fclose(InFile);
return;
}
/* RETURNS THE ISO 11 EQUIVALENT OF AN 8-BIT UNSIGNED CHARACTER */
static uchar ToIso11(uchar c) {
switch (c) {
case 0304 : c = '[' ; break; /* A" */
case 0344 : c = '{' ; break; /* a" */
case 0326 : c = '|' ; break; /* O", intentionally _NOT_ '\\' */
case 0366 : c = '|' ; break; /* o" */
case 0305 : c = ']' ; break; /* A' */
case 0345 : c = '}' ; break; /* a' */
case 0334 : c = '^' ; break; /* U" */
case 0374 : c = '~' ; break; /* u" */
case 0311 : c = '@' ; break; /* E' */
case 0351 : c = '`' ; break; /* e' */
case 0253 : c = '"' ; break; /* << */
case 0273 : c = '"' ; break; /* >> */
default : if (c > 126) c = '?'; break;
}
return c;
}
/* SHOWS FORTUNES THAT HAVE THE SPECIFIED STRING IN THEM */
static void GrepFortunes(uchar *FromStr, BOOL Sensitive) {
static uchar GrepStr[80];
static uchar Last[80];
int Curr = 1, LastLoc = 0;
BOOL OldSigMode = SignatureMode,
OldLOMode = LongOutputMode,
SkipUntilEndOfFortune = FALSE;
static FILE *InFile;
static int InC, GrepStrLen, i;
unsigned long Last4 = 0, Magic = 0, MagicGrepStr = 0;
static char Line[71] =
"----------------------------------------------------------------------";
SignatureMode = FALSE;
LongOutputMode = FALSE;
GrepStr[0] = '\000';
for (i = 0; i < 80 && FromStr[i]; i++) {
if (Sensitive) GrepStr[i] = FromStr[i];
else GrepStr[i] = ToUpper(FromStr[i]);
MagicGrepStr += GrepStr[i];
Last[i] = 0;
}
GrepStr[79] = '\000';
GrepStrLen = strlen((char *) GrepStr);
if (!GrepStrLen) return;
if (!(InFile = fopen(FFile,"rb"))) {
fprintf(stderr,"Couldn't open fortune file %s for reading!\n",FFile);
exit(EXIT_FAILURE);
}
Bufferize(InFile);
i = 20 + strlen((char *) GrepStr);
if (i > 70) i = 70;
printf("---------- Grep: \"%s\" %s\n", GrepStr, &Line[i]);
while ((InC = fgetc(InFile)) != -1) {
Last4 = (Last4 << 8) | InC;
if (!Sensitive) InC = ToUpper(InC);
if (InC == '\n') InC = ' ';
LastLoc++;
if (LastLoc >= GrepStrLen) LastLoc = 0;
Magic -= Last[LastLoc];
Magic += InC;
Last[LastLoc] = InC;
if (Last4 == FEnd0 || Last4 == FEnd1) {
Curr++;
SkipUntilEndOfFortune = FALSE;
}
if (Magic == MagicGrepStr && !SkipUntilEndOfFortune) {
int k = LastLoc, ok = TRUE;
for (i=GrepStrLen-1; i>=0; i--) {
if (Last[k] != GrepStr[i]) ok = FALSE;
k--;
if (k<0) k = GrepStrLen-1;
}
if (ok) {
ShowFortune(Curr);
printf("%s\n", Line);
SkipUntilEndOfFortune = TRUE;
}
}
}
fclose(InFile);
SignatureMode = OldSigMode;
LongOutputMode = OldLOMode;
}
/* RETURNS THE CURRENT TIME IN FIFTIETH OF SECONDS, AMIGA SPECIFIC */
#if defined _AMIGA || defined AMIGA
static ULONG GetAmigaTicks(void) {
static struct DateStamp ds;
DateStamp(&ds);
return (ULONG) ((ULONG) ds.ds_Tick +
((ULONG) ds.ds_Minute +
(ULONG) ds.ds_Days*24*60)*60*TICKS_PER_SECOND);
}
#endif
/***********************************\
* *
* Text displaying put-routines *
* *
\***********************************/
static FILE *PutFile=NULL;
static int PutPos, PutMaxColumn = 79, PutLines, PutIndent;
static BOOL PutLastSpace;
static void PutInit(FILE *OutFile) {
PutFile = OutFile;
PutPos = 0;
PutLastSpace = FALSE;
PutLines = 0;
PutIndent = 0;
}
static void PutWord(uchar *Str) {
static int Len;
Len = strlen((char *) Str);
if (PutPos + Len >= PutMaxColumn) {
if (PutFile) fputc('\n', PutFile);
PutPos = 0;
PutLines++;
PutDoIndent();
if (PutFile) fprintf(PutFile, "%s", Str);
PutPos += Len - 1;
} else {
if (PutLastSpace) {
if (PutFile) fputc(' ', PutFile);
PutPos++;
}
if (PutFile) fprintf(PutFile, "%s", Str);
PutPos += Len;
}
PutLastSpace = FALSE;
}
static void PutEOL(void) {
if (PutFile) fputc('\n', PutFile);
PutPos = 0;
PutLines++;
PutLastSpace = FALSE;
PutSetIndent(FALSE);
}
static void PutTab(void) {
PutPurgeSpace();
if (PutFile) fputc('\t', PutFile);
PutPos = (PutPos + 8) & (~7);
}
static void PutSpace(void) {
if (PutLastSpace) {
PutLastSpace = FALSE;
PutWord(" ");
}
PutLastSpace = TRUE;
}
static void PutPurgeSpace(void) {
if (PutLastSpace) {
if (PutPos + 1 >= PutMaxColumn) {
if (PutFile) fputc('\n', PutFile);
PutPos = 0;
PutLines++;
PutDoIndent();
} else {
if (PutFile) fputc(' ', PutFile);
PutPos++;
}
}
PutLastSpace = FALSE;
}
static void PutSetWidth(int Width) {
if (Width < 20) Width = 20;
PutMaxColumn = Width - 1;
}
static int PutEnd(void) {
return PutLines;
}
static void PutSetIndent(BOOL On) {
PutPurgeSpace();
if (On) PutIndent = PutPos;
else PutIndent = 0;
}
static void PutDoIndent(void) {
if (PutIndent <= PutMaxColumn-20) {
while (PutPos < PutIndent) {
if (PutFile) fputc(' ', PutFile);
PutPos++;
}
}
}
/* SHOWS A FORTUNE FILE FROM MEMORY */
static int ShowFortuneFromMem(FILE* OutFile, uchar *FortuneText, long FortuneLength) {
static uchar Word[80];
int WordLen = 0;
BOOL LastNL = TRUE, LastEscape = FALSE;
static int InC;
static long i;
if (SignatureMode) {
PutSetWidth(WW_DEFWIDTH);
} else {
PutSetWidth(WordWrapWidth);
}
PutInit(OutFile);
for (i=0; i<FortuneLength; i++) {
InC = FortuneText[i];
if (InC == '\\' && i<FortuneLength-1 && !LastEscape) {
switch (FortuneText[i+1]) {
case '<':
PutSetIndent(FALSE);
i++;
break;
case '>':
if (WordLen) {
PutWord(Word);
WordLen = 0;
}
PutSetIndent(TRUE);
i++;
break;
default:
LastEscape = 2;
break;
}
} else if (InC == '\n') {
if (LastNL) {
if (WordLen) {
PutWord(Word);
WordLen = 0;
}
PutEOL();
} else {
if (WordLen) {
PutWord(Word);
WordLen = 0;
}
PutSpace();
}
} else if (InC == '\t') {
if (WordLen) {
PutWord(Word);
WordLen = 0;
}
PutTab();
} else {
if (InC == ' ') {
if (WordLen) {
PutWord(Word);
WordLen = 0;
}
PutSpace();
} else {
if (WordLen < 78) {
Word[WordLen] = InC;
Word[++WordLen] = '\000';
}
}
}
LastNL = (InC == '\n');
if (LastEscape) LastEscape--;
}
PutEOL();
return PutEnd();
}
/* CONNECT A FILE TO A 16 KB IO-BUFFER TO ENHANCE FILE HANDLING. */
/* NOTE: ONLY ONE FILE AT A TIME MAY HAVE THIS BUFFER! */
/* THIS FUNCTION MUST BE CALLED IMMEDIATELY AFTER FOPEN()! */
static void Bufferize(FILE *File) {
if (!InBuff) InBuff = malloc(16384);
if (InBuff) setvbuf(File, InBuff, _IOFBF, (size_t) 16384);
}